package com.vois.jack.btmgr.classicbase;

import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.media.AudioManager;
import android.os.Bundle;
import android.os.Message;
import android.text.TextUtils;

import com.vois.jack.btmgr.common.DeviceRecorderControlInterface;
import com.vois.jack.btmgr.util.Logger;

import java.util.UUID;

public abstract class BtDevice implements DeviceRecorderControlInterface {
    private Logger logger = Logger.getLogger(BtDevice.class);
    private BluetoothDevice device;
    private BtDevFsm btDevFsm;
    private BtDeviceListener listener;
    private boolean isInited;
    private int currentState;
    private long lastDisconnectedTimestamp;
    private ResultCallback openScoResultCb;
    private ResultCallback closeScoResultCb;
    private boolean isScoOn;

    public static final int SPP_CONNECTED       = 0x01;
    public static final int SPP_CONNECTING      = 0x02;
    public static final int SPP_DISCONNECTED    = 0x03;

    public interface BtDeviceListener {
        void onInited(BtDevice device);
        void onConnectStateChanged(BtDevice device, int profile, int state);
        void onSppStateChanged(BtDevice device, int status);
        void onScoStateChanged(BtDevice device, int state);
        void onMessage(BtDevice device, Message message);
        void onClosed(BtDevice device);
        void onError(BtDevice device, int type, BtErrorCode code);
    }

    void init(BluetoothDevice device) {
        this.device = device;
        currentState = BluetoothProfile.STATE_DISCONNECTED;
    }

    public void openDevice() {
        logger.d("openDevice: btDevFsm is null? " + (btDevFsm == null));
        isScoOn = false;
        if (btDevFsm != null) {
            btDevFsm.detachDevice();
            btDevFsm.stopFsm();
            btDevFsm = null;
        }

        btDevFsm = new BtDevFsm(this);
        btDevFsm.start();
    }

    public void closeDevice() {
        logger.d("closeDevice: btDevFsm is null? " + (btDevFsm == null));
        if (btDevFsm != null) {
            btDevFsm.stopFsm();
            btDevFsm = null;
        }
    }

    @Override
    public boolean startRecorder(ResultCallback callback) {
        openScoResultCb = callback;
        return openSco();
    }

    @Override
    public void stopRecorder(ResultCallback callback) {
        if (openScoResultCb != null) {
            openScoResultCb.onResult(false);
            openScoResultCb = null;
        }

        closeScoResultCb = callback;
        closeSco();
    }

    protected BtDeviceListener getListener() {
        return listener;
    }

    public BluetoothDevice getDevice() {
        return device;
    }

    public String getMac(){
        final BluetoothDevice bluetoothDevice = getDevice();
        return  (bluetoothDevice == null ? "" : bluetoothDevice.getAddress());
    }

    public void setDevice(BluetoothDevice device) {
        this.device = device;
    }

    public void setListener(BtDeviceListener listener) {
        this.listener = listener;
    }

    abstract protected void onSppDataRecv(byte[] buffer, int bufferSize);

    abstract protected int getMaxSppPacketDataSize();

    protected int getConnectTimeout() {
        return 5000;
    }

    protected int getConnectTimeoutTry() {
        return 6;
    }

    @Override
    public int getSampleRate() {
        return 16000;
    }

    abstract protected UUID getSppConnectUUID();

    void onBtError(int type, BtErrorCode code) {
        if (listener != null) {
            listener.onError(this, type, code);
        }
    }

    protected void onFsmQuit() {
        if (listener != null) {
            listener.onClosed(this);
        }
    }

    protected int getScoAudioMode() {
        return AudioManager.MODE_NORMAL;
    }

    protected void onSppSocketConnected() {
        if (listener != null) {
            listener.onSppStateChanged(this, SPP_CONNECTED);
        }
    }

    protected void onSppSocketConnecting() {
        if (listener != null) {
            listener.onSppStateChanged(this, SPP_CONNECTING);
        }
    }

    protected void onSppSocketErrorOrClose() {
        disconnectSpp();
        connectSpp();
    }

    protected void onSppSocketDisconnected() {
        if (listener != null) {
            listener.onSppStateChanged(this, SPP_DISCONNECTED);
        }
    }

    protected void onBtConnectStateChanged(int profile, int curState) {
        logger.d( "onBtConnectStateChanged: " + profile + " :" + curState);
        if (profile == BluetoothProfile.HEADSET) {
            currentState = curState;
            if (curState == BluetoothProfile.STATE_DISCONNECTED) {
                lastDisconnectedTimestamp = System.currentTimeMillis();
                if (isScoOn) {
                    closeSco();
                }
            }else {
                lastDisconnectedTimestamp = 0;
            }
        }

        if (listener != null) {
            listener.onConnectStateChanged(this, profile, curState);
        }
    }

    protected void onScoStateChanged(int state) {
        if (state == AudioManager.SCO_AUDIO_STATE_DISCONNECTED) {
            isScoOn = false;
            if (closeScoResultCb != null) {
                closeScoResultCb.onResult(true);
                closeScoResultCb = null;
            }
        }else if (state == AudioManager.SCO_AUDIO_STATE_CONNECTED) {
            isScoOn = true;
            if (openScoResultCb != null) {
                openScoResultCb.onResult(true);
                openScoResultCb = null;
            }
        }

        if (listener != null) {
            listener.onScoStateChanged(this, state);
        }
    }

    public void processXEvent(String cmd, int cmdType, Object[] args) {
        logger.d( "processXEvent: ");
    }

    public void processA2DPConnectState(int curState, int preState) {
        if (btDevFsm != null) {
            btDevFsm.notifyA2DPConnectChanged(curState, preState);
        }
    }

    public void processHeadsetConnectState(int curState, int preState) {
        if (btDevFsm != null) {
            btDevFsm.notifyHeadsetConnectChanged(curState, preState);
        }
    }

    public void processHeadsetScoState(int state) {
        if (btDevFsm != null) {
            btDevFsm.notifyHeadsetScoChanged(state);
        }
    }

    public boolean connectSpp() {
        if (btDevFsm != null) {
            return btDevFsm.startConnectSpp();
        }

        return false;
    }

    public boolean disconnectSpp() {
        if (btDevFsm != null) {
            return btDevFsm.disconnectSpp();
        }

        return false;
    }

    public void disconnect() {
        if (btDevFsm != null) {
            btDevFsm.disconnect();
        }
    }

    public boolean openSco() {
        if (btDevFsm != null) {
            logger.d("open sco");
            return btDevFsm.startScoAction();
        }

        return false;
    }

    public boolean closeSco() {
        if (btDevFsm != null) {
            logger.d("close sco");
            isScoOn = false;
            return btDevFsm.stopScoAction();
        }

        return false;
    }

    public void putSppSendData(byte[] data, int dataSize) {
        if (btDevFsm != null) {
            btDevFsm.putSendingData(data, dataSize);
        }else {
            logger.e("btDevFsm is null!");
        }
    }

    void onInit() {
        isInited = true;
        if (listener != null) {
            listener.onInited(this);
        }
    }

    public boolean isInited() {
        return isInited;
    }

    public abstract String getDeviceType();

    public abstract String getProtocolName();

    public boolean isHeadsetConnected() {
        logger.d( "isHeadsetConnected: " + (currentState == BluetoothProfile.STATE_CONNECTED));
        if (btDevFsm != null) {
            logger.d("isHeadsetConnected: curState:" + btDevFsm.getCurState());
        }
        return currentState == BluetoothProfile.STATE_CONNECTED;
    }

    public boolean isNeedHeartbeat() {
        return true;  //会影响蓝牙耳机暂停和恢复音乐的功能，关闭后，功能就会正常
    }

    public long getLastDisconnectedTimestamp() {
        return lastDisconnectedTimestamp;
    }

    public boolean useOwnPlayTone() {
        return false;
    }

    public boolean isNeedValidation() {
        return false;
    }

    public void getValidateData() {
    }

    //统一流程因此增加了获取地址接口 实际取的的系统的蓝牙地址
    // 目前验证没用address, 担心设备未实现取地址协议，因此目前未走协议取
    public void getAddress(){
        if (listener != null) {
            final String mac = getMac();
            final String address = (TextUtils.isEmpty(mac) ? "" : mac.replaceAll(":", "").toLowerCase());
            Message message = Message.obtain();
            message.what = BtDevCommonMsg.BT_DEV_GET_ADDRESS_RET.getValue();
            Bundle bundle = new Bundle();
            bundle.putString(BtDevConstant.EXTRA_ADDRESS, address);
            message.setData(bundle);
            listener.onMessage(this, message);
        }
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof BtDevice) {
            BtDevice btDevice = (BtDevice) obj;
            return btDevice.getDevice().getAddress().equals(device.getAddress());
        }

        return true;
    }

    public BtDevFsm getBtDevFsm() {
        return btDevFsm;
    }

    public abstract void setSeqID(String seqID);

    public abstract void getVendor();

    public abstract void getVersion();


}
